package com.hcss.common.util;

import com.google.zxing.BarcodeFormat;
import com.google.zxing.EncodeHintType;
import com.google.zxing.MultiFormatWriter;
import com.google.zxing.WriterException;
import com.google.zxing.common.BitMatrix;
import com.google.zxing.qrcode.decoder.ErrorCorrectionLevel;

import java.awt.*;
import java.awt.geom.RoundRectangle2D;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.util.Hashtable;
import java.util.Map;

/**
 * 二维码工具类生成
 */
public class QRCodeUtil {
	public static final String CHARSET = "UTF-8";

	public static final String FORMAT_NAME = "png";
	// 二维码 默认尺寸
	public static final int QRCODE_SIZE = 300;
	// LOGO 默认宽度
	public static final int WIDTH = 75;
	// LOGO 默认高度
	public static final int HEIGHT = 75;

	// 底部需要文字描述 二维码需延长的空白默认高度
	public static final int TEMPHEIGHT = 60;

	/**
	 * 创建 二维码所需图片
	 * 
	 * @param content
	 *            内容
	 * @param imgPath
	 *            Logo图片地址
	 * @param needDescription
	 *            是否需要底部文字描述
	 * @param ycheight
	 *            图片延长高度
	 * @return
	 * @throws Exception
	 */
	public static BufferedImage createImage(String content, BufferedImage logoImage, String bottomDes,
			boolean needCompress, int width, int height, int logowidth, int logoheight, int ycheight, Font font) {
		Map<EncodeHintType, Object> hints = new Hashtable<>();
		hints.put(EncodeHintType.ERROR_CORRECTION, ErrorCorrectionLevel.H); // 容错级别 H->30%
		hints.put(EncodeHintType.CHARACTER_SET, CHARSET);
		hints.put(EncodeHintType.MARGIN, 1);
		if (width == 0) {
            width = QRCODE_SIZE;
        }
		if (height == 0) {
            height = QRCODE_SIZE;
        }
		BitMatrix bitMatrix;
		BufferedImage image = null;
		try {
			bitMatrix = new MultiFormatWriter().encode(content, BarcodeFormat.QR_CODE, width, height, hints);
			width = bitMatrix.getWidth();
			height = bitMatrix.getHeight();
			int tempHeight = height;
			boolean needDescription = (bottomDes != null && !("").equals(bottomDes));
			if (needDescription) {
				if (ycheight == 0) {
					tempHeight += TEMPHEIGHT;
				} else {
					tempHeight += ycheight;
				}
			}
			image = new BufferedImage(width, tempHeight, BufferedImage.TYPE_INT_RGB);
			for (int x = 0; x < width; x++) {
				for (int y = 0; y < height; y++) {
					image.setRGB(x, y, bitMatrix.get(x, y) ? 0xFF000000 : 0xFFFFFFFF);
				}
			}
			if (logoImage != null) {
				// 插入图片
				insertImage(image, logoImage, needCompress, logowidth, logoheight, width, height);
			}
			if (!needDescription) {
                return image;
            }
			// 添加文字
			addFontImage(image, bottomDes, font, width, ycheight);
		} catch (WriterException e) {
			e.printStackTrace();
		}

		return image;
	}

	/**
	 * 添加 底部图片文字
	 * 
	 * @param source
	 *            图片源
	 * @param declareText
	 *            文字本文
	 */
	public static void addFontImage(BufferedImage source, String declareText, Font font, int width, int height) {
		if (declareText == null || source == null) {
            return;// 未传入底部文字获取 带插入logo的图片未空，则返回
        }
		BufferedImage textImage = null;

		if (width == 0) {
            width = QRCODE_SIZE;
        }
		if (font == null) {
			textImage = FontImage.getImage(declareText, width, 80);
		} else {
			textImage = FontImage.getImage(declareText, font, width, height);
		}
		Graphics2D graph = source.createGraphics();
		int widths = textImage.getWidth(null);
		int heights = textImage.getHeight(null);
		
		Image src = textImage;
		graph.drawImage(src, 0, 300, widths, heights, null);
		graph.dispose();
	}

	/**
	 * 插入Logo图片
	 * 
	 * @param source
	 *            图片操作对象
	 * @param needCompress
	 *            是否压缩Logo大小
	 * @throws Exception
	 */
	public static void insertImage(BufferedImage source, BufferedImage logoImage, boolean needCompress, int logowidth,
			int logoheight, int QRwidth, int QRhieght){

		if (logoImage == null || source == null) {
            return;
        }

		int width = logoImage.getWidth(null);
		int height = logoImage.getHeight(null);
		if (logowidth == 0) {
            logowidth = WIDTH;
        }
		if (logoheight == 0) {
            logoheight = HEIGHT;
        }
		if (QRwidth == 0) {
            QRwidth = QRCODE_SIZE;
        }
		if (QRhieght == 0) {
            QRhieght = QRCODE_SIZE;
        }
		Image src = logoImage;
		if (needCompress) {
			if (width > logowidth) {
				width = logowidth;
			}
			if (height > logoheight) {
				height = logoheight;
			}

			Image image = logoImage.getScaledInstance(width, height, Image.SCALE_SMOOTH);
			BufferedImage tag = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
			Graphics g = tag.getGraphics();
			g.drawImage(image, 0, 0, null);
			g.dispose();
			src = image;
		}
		Graphics2D graph = source.createGraphics();
		int x = (QRwidth - width) / 2;
		int y = (QRhieght - height) / 2;
		graph.drawImage(src, x, y, width, height, null);
		Shape shape = new RoundRectangle2D.Float(x, y, width, width, 6, 6);
		graph.setStroke(new BasicStroke(3f));
		graph.draw(shape);
		graph.dispose();
	}

	/**
	 * 递归创建对应的目录
	 * 
	 * @param filePath
	 * @throws IOException
	 */
	public static boolean mkdirs(String path) throws IOException {
		boolean result = true;
		File file = null;
		// 注： 这里对linux处理是有问题的 filePath = filePath.replace("/", "\\");
		path = path.replace("\\", "/");
		for (int i = 0; i < path.length();) {
			i = path.indexOf("/", i + 1);
			if (i != -1) {
				String dir = path.substring(0, i);
				file = new File(dir);
				if (!file.exists()) {
					result = file.mkdir();
				}
			} else {
				file = new File(path);
				if (!file.exists()) {
					result = file.mkdir();
				}
				break;
			}
		}
		return result;
	}

	/**
	 * @param content二维码内容
	 * @param logoImage
	 *            logo 如果不需要 传 null
	 * @param bottomDes
	 *            底部文字描述，如果不需要 传 null
	 * @param needCompress
	 *            logo 是否需要压缩 选择true or false logoImage==null 则该参数无效
	 * @param destPath
	 *            生产的二维码保持路径
	 * @param picName
	 *            二维码名称
	 * @param width
	 *            二维码 width 若传 width==0 则默认width=300
	 * @param height
	 *            二维码 height 若传 height==0 则默认height=300
	 * @param logowidth
	 *            logo 的width 若传 width==0 则默认width=75
	 * @param logoheight
	 *            logo 的height 若传 height==0 则默认height=75
	 * @param ycheight
	 *            二维码延申高度，需要添加底部二维码时，则需延长二维码高度，ycheight==0 则 默认 ycheight=60
	 * @param font
	 *            底部文字描述 字体
	 * @throws Exception
	 */

	public static void encode(String content, BufferedImage logoImage, String bottomDes, boolean needCompress,
			String destPath, String picName, int width, int height, int logowidth, int logoheight, int ycheight,
			Font font) throws Exception {
		// 生产二维码
		BufferedImage image = createImage(content, logoImage, bottomDes, needCompress, width, height, logowidth,
				logoheight, ycheight, font);

		addFontImage(image, "18", font, 300, 80);
	}
}
